/*
 * Copyright (C) 2020 UNISOC Open Source Project
 *
 */

package com.android.systemui.screenshot;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Icon;
import android.media.MediaActionSound;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.provider.Settings;
import android.database.ContentObserver;

import com.android.internal.util.LongScreenshotUtil;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.phone.StatusBar;

import com.unisoc.systemui.screenshot.CompareTask;
import com.unisoc.systemui.screenshot.ScreenshotMoreActionSelectorView;
import com.unisoc.systemui.superpower.UnisocPowerManagerUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;

import javax.inject.Inject;
import javax.inject.Singleton;

import dagger.Lazy;
import android.content.res.Configuration;
import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
import static android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED;
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT;

import static com.unisoc.systemui.screenshot.CommonUtils.disableAssistantIfNeeded;
import static com.unisoc.systemui.screenshot.CommonUtils.enableAssistantIfNeeded;
import static com.unisoc.systemui.screenshot.CommonUtils.isInRegionOrLongshotMode;
import static com.unisoc.systemui.screenshot.CommonUtils.setRegionOrLongshotMode;

/**
 * Class for handling unisoc device screen shots with more actions
 */
@Singleton
public class GlobalScreenshotMoreAction implements ViewTreeObserver.OnComputeInternalInsetsListener {

    /**
     * Used in the AsyncTask which compare two images in the background.
     */
    public static class CompareImageInBackgroundData {
        public Bitmap previousBitmap;
        public Bitmap currentBitmap;
        //UNISOC: Add for bug 1361055
        public float scale;
        public CompareCompleteListener compareCompleteListener;

        public void clearImage() {
            previousBitmap.recycle();
            currentBitmap.recycle();
            previousBitmap = null;
            currentBitmap = null;
            //UNISOC: Add for bug 1361055
            scale = 0;
        }
    }

    public abstract static class CompareCompleteListener {
        public abstract void onCompareComplete(Bitmap croped);
    }

    /**
     * Used in the AsyncTask which swipe the screen in the background.
     */
    public static class SwipeInBackgroundData {
        public Context context;
        public int screenWidth;
        public int screenHeight;
        //UNISOC: Add for bug 1361055
        public float scale;
        public SwipeSentListener swipeSentListener;
    }

    public abstract static class SwipeSentListener {
        public abstract void onSwipeSent();
    }

    public static final int SCREENSHOT_TOP_MAGIN_SPLIT_HEIGHT_COUNT = 4; // one quarter of screen height

    private static final String TAG = "GlobalScreenshotMoreAction";

    private static final long SCREENSHOT_FLASH_IN_DURATION_MS = 133;
    private static final long SCREENSHOT_FLASH_OUT_DURATION_MS = 217;
    private static final long SCREENSHOT_TO_CORNER_X_DURATION_MS = 234;
    private static final long SCREENSHOT_TO_CORNER_Y_DURATION_MS = 500;
    private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
    private static final long CAPTURE_SCREENSHOT_AND_PREPARE_DELAY_MS = 280;
    private static final float ROUNDED_CORNER_RADIUS = .05f;
    private static final long SCREENSHOT_CORNER_TIMEOUT_MILLIS = 6000;
    private static final int MESSAGE_CORNER_TIMEOUT = 2;
    private static final float SCREENSHOT_MORE_ACTION_DROP_IN_SCALE = 0.75f;
    private static final boolean DEBUG_REGION = false;
    private static final int MSG_START_SWIPE = 10;
    private static final int MSG_CAPTURE_SCREENSHOT_AND_PREPARE = 11;
    //UNISOC: Add for bug 1358959
    private static final int STANDARD_HEIGHT = 2160;//sharkl5pro resolution
    /*UNISOC: Add for bug 1361055 @{*/
    private static int STANDARD_DENSITY = 480;//sharkl5pro lcd density
    private static final float STANDARD_FONT_SCALE = 0.023f;//UI offset for font scale
    /*}@*/

    private final ScreenshotNotificationsController mNotificationsController;

    private Context mContext;
    private final WindowManager mWindowManager;
    private final WindowManager.LayoutParams mWindowLayoutParams;
    private final WindowManager.LayoutParams mMoreActionWindowLayoutParams;
    private final WindowManager.LayoutParams mLongScreenshotTipLayoutParams;
    private Display mDisplay;
    private DisplayMetrics mDisplayMetrics;

    private View mScreenshotLayout;
    private ScreenshotMoreActionSelectorView mScreenshotMoreActionSelectorView;
    private ImageView mBackgroundView;
    private ImageView mScreenshotView;
    private ImageView mScreenshotFlash;
    private final HorizontalScrollView mActionsContainer;
    private final LinearLayout mActionsView;
    private ImageView mBackgroundProtection;
    private FrameLayout mDismissButton;

    private Bitmap mScreenBitmap;
    private Animator mScreenshotAnimation;

    private float mScreenshotOffsetXPx;
    private float mScreenshotOffsetYPx;
    private float mScreenshotHeightPx;
    private float mDismissButtonSize;
    private float mCornerSizeX;

    private AsyncTask<Void, Void, Void> mSaveInBgTask;

    private MediaActionSound mCameraSound;
    private ImageView mImageview;
    private View mMoreActionLayout;
    private View mLongScreenshotTips;
    private boolean mIsCancelLongScreenshot;
    private boolean mCompleteLongScreenshot;
    private boolean mDuplicateNotFound;
    private boolean mIsLongscreenshotStarting = false;
    private boolean mIsMultiWindowMode = false;
    private static final int LONG_BITMAP_HEIGHT_LIMIT = 20 * 1024;
    private Bitmap mPreviousBitmap;
    private final List<Bitmap> mCropedBitmapsResultList;
    private TakeScreenshotService mTakeScreenshotService;
    private Consumer<Uri> mFinisher;
    private Runnable mOnCompleteRunnable;
    private boolean mInDarkMode = false;
    // standard material ease
    private Interpolator mFastOutSlowIn;
    private float mDensity;

    /* UNISOC: Modify for bug1389430,1395899 @{ */
    private static final String ACTION_SR_CHANGING = "sprd.action.super_resolution_state";
    private ContentObserver mScreenResolutionObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
            Log.d(TAG, "screen resolution onChange selfChange=" + selfChange);
            int srChanging = Settings.Global.getInt(mContext.getContentResolver(), ACTION_SR_CHANGING, 0);
            try {
                if (mScreenshotLayout.isAttachedToWindow() && srChanging == 1) {
                    clearScreenshot("resolution_change");
                    enableAssistantIfNeeded(mContext);
                    setRegionOrLongshotMode(mContext, 0);
                    mOnCompleteRunnable.run();
                }
            } catch (Exception e) {
                Log.d(TAG, "resolution change error!");
            }
        }

    };
    /* @} */

    private final Handler mScreenshotHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_CORNER_TIMEOUT:
                    saveScreenshotInWorkerThread(new GlobalScreenshot.ActionsReadyListener() {
                        @Override
                        void onActionsReady(GlobalScreenshot.SavedImageData imageData) {
                            Log.v(TAG, "save screenshot complete.");
                            setRegionOrLongshotMode(mContext, 0);
                            mOnCompleteRunnable.run();
                        }
                    });
                    GlobalScreenshotMoreAction.this.clearScreenshot("timeout");
                    //UNISOC: Add for bug 1372730
                    enableAssistantIfNeeded(mContext);
                    break;
                case MSG_START_SWIPE:
                    startSwipe();
                    break;
                case MSG_CAPTURE_SCREENSHOT_AND_PREPARE:
                    captureScreenshotAndCompare();
                    break;
                default:
                    break;
            }
        }
    };

    private BroadcastReceiver mStopLongScreenshotReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "onReceive action:" + action);
            if (LongScreenshotUtil.ACTION_STOP_LONGSCREENSHOT.equals(action)) {
                mIsCancelLongScreenshot = intent.getBooleanExtra(LongScreenshotUtil.LONGSCREENSHOT_CANCEL, false);
            } else if (Intent.ACTION_SCREEN_OFF.equals(action)
                    || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                    || ACTION_PHONE_STATE_CHANGED.equals(action)
                    || UnisocPowerManagerUtil.ACTION_POWEREX_SAVE_MODE_CHANGED.equals(action)) {  //Unisoc: Add for bug 1428157
                mIsCancelLongScreenshot = true;
            }

            if (mIsLongscreenshotStarting) {
                if (mIsCancelLongScreenshot) {
                    cancelLongscreenshot();
                } else {
                    stopLongscreenshotByUser();
                }
            } else {
                stopScreenshot();
                setRegionOrLongshotMode(mContext, 0);
                mOnCompleteRunnable.run();
            }
        }
    };

    private void startSwipe() {
        Log.d(TAG, "startSwipe");
        if (mScreenBitmap == null) {
            Log.e(TAG, "mScreenBitmap is null!");
            stopLongscreenshot();
            return;
        }
        if (mIsCancelLongScreenshot) {
            Log.d(TAG, "startSwipe canceled");
            stopLongscreenshot();
            return;
        }
        if (mCropedBitmapsResultList.size() == 0) {
            Log.d(TAG, "startSwipe no first bitmap");
            stopLongscreenshot();
            return;
        }
        SwipeInBackgroundData data = new SwipeInBackgroundData();
        data.context = mContext;
        data.screenWidth = mScreenBitmap.getWidth();
        data.screenHeight = mScreenBitmap.getHeight();
        //UNISOC: Add for bug 1361055
        data.scale = getScale();
        data.swipeSentListener = new SwipeSentListener() {
            @Override
            public void onSwipeSent() {
                mScreenshotHandler.removeMessages(MSG_CAPTURE_SCREENSHOT_AND_PREPARE);
                mScreenshotHandler.sendEmptyMessageDelayed(MSG_CAPTURE_SCREENSHOT_AND_PREPARE,
                        CAPTURE_SCREENSHOT_AND_PREPARE_DELAY_MS);
            }
        };
        new SwipeTask(data).execute();
    }

    /*
    *UNISOC: Add for bug 1361055
    * Adaptation resolution&font&density change.
    */
    private float getScale() {
        //UNISOC: Add for bug 1358959
        float resolutionScale = 0f;
        final int deviceDensity = SystemProperties.getInt("ro.sf.lcd_density", STANDARD_DENSITY);
        final float fontScale = Settings.System.getFloat(mContext.getContentResolver(), Settings.System.FONT_SCALE, 1.0f);
        final int overrideDensity = (int)(mDisplayMetrics.scaledDensity * 160);
        final float fontScaleDiff = fontScale - 1.0f;
        /*UNISOC: Add for bug 1358959 @{*/
        if (mDisplayMetrics.heightPixels != STANDARD_HEIGHT && deviceDensity == STANDARD_DENSITY) {
            resolutionScale = (float)(STANDARD_HEIGHT - mDisplayMetrics.heightPixels) / mDisplayMetrics.heightPixels;
        }

        Log.d(TAG, "device density = =" + deviceDensity + " : DisplayMetrics = " + mDisplayMetrics.toString()
            + overrideDensity + " : fontScale = " + fontScale + "resolutionScale = " + resolutionScale);
        return (float)overrideDensity / deviceDensity + (fontScaleDiff > 0 ? fontScaleDiff : 0) * STANDARD_FONT_SCALE
                   + (resolutionScale > 0 ? resolutionScale : 0);
        /*}@*/
    }

    private void prepareFirstBitmap() {
        Log.d(TAG, "prepareFirstBitmap");
        mCropedBitmapsResultList.clear();
        Bitmap firstBitmap = mScreenBitmap.copy(Bitmap.Config.ARGB_8888, true);
        CompareImageInBackgroundData data = new CompareImageInBackgroundData();
        data.previousBitmap = null;
        //UNISOC: Add for bug 1361055
        data.scale = getScale();
        data.currentBitmap = firstBitmap;
        data.compareCompleteListener = new CompareCompleteListener() {
            @Override
            public void onCompareComplete(Bitmap croped) {
                if (croped != null) {
                    mCropedBitmapsResultList.add(croped);
                    Log.d(TAG, "first bitmap added");
                }
            }
        };
        new CompareTask(data).execute();
        mPreviousBitmap = firstBitmap;
    }

    private void captureScreenshotAndCompare() {
        Bitmap bitmap = captureScreenshotBitmap();
        if (bitmap != null) {
            //UNISOC: Add for bug 1364810
            bitmap.setHasAlpha(false);
            Bitmap screenshot = bitmap.copy(Bitmap.Config.ARGB_8888, true);
            bitmap.recycle();
            CompareImageInBackgroundData data = new CompareImageInBackgroundData();
            data.previousBitmap = mPreviousBitmap;
            data.currentBitmap = screenshot;
            //UNISOC: Add for bug 1361055
            data.scale = getScale();
            data.compareCompleteListener = new CompareCompleteListener() {
                @Override
                public void onCompareComplete(Bitmap croped) {
                    if (mIsCancelLongScreenshot) {
                        Log.d(TAG, "longscreenshot is canceled");
                        stopLongscreenshot();
                        return;
                    }
                    /*UNISOC: Add for bug 1368791 @{*/
                    if (UnisocPowerManagerUtil.isSuperPower()) {
                        stopLongscreenshot();
                        clearScreenshot("superpower");
                        return;
                    }
                    /*}@*/
                    if (croped != null) {
                        mCropedBitmapsResultList.add(croped);
                        Log.d(TAG, "add bitmap:" + croped.getHeight());
                        if (!limitHeight() && !mCompleteLongScreenshot) {
                            mScreenshotHandler.removeMessages(MSG_START_SWIPE);
                            mScreenshotHandler.sendEmptyMessageDelayed(MSG_START_SWIPE, 0);
                            return;
                        }
                    }

                    // End long screen shot
                    setLongScreenshotTipsText(R.string.tip_merging);
                    saveLongScreenshotInWorkerThread(new GlobalScreenshot.ActionsReadyListener() {
                        @Override
                        void onActionsReady(GlobalScreenshot.SavedImageData imageData) {
                            Log.d(TAG, "save long screen shot complete:" + imageData.uri);
                            if (mIsCancelLongScreenshot) {
                                Log.d(TAG, "screenshot is canceled, delete and do not preview");
                                try {
                                    imageData.deleteAction.actionIntent.send();
                                } catch (PendingIntent.CanceledException e) {
                                    Log.e(TAG, "Intent cancelled", e);
                                }
                            } else {
                                /* UNISOC: Modify for bug 1417116 @{ */
                                if (null != imageData.uri) {
                                    // Create the intent to show the screenshot in gallery
                                    Intent viewIntent = new Intent(Intent.ACTION_VIEW);
                                    viewIntent.setDataAndType(imageData.uri, "image/png");
                                    viewIntent.setFlags(
                                            Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                                    mContext.startActivityAsUser(viewIntent, UserHandle.CURRENT);
                                } else {
                                    mNotificationsController.notifyScreenshotError(
                                            R.string.screenshot_failed_to_save_text);
                                }
                                /* @} */
                            }
                            stopLongscreenshot();
                        }
                    });
                }
            };
            new CompareTask(data).execute();
            mPreviousBitmap = screenshot;
        }
    }

    private boolean limitHeight() {
        int height = 0;
        for (Bitmap bitmap : mCropedBitmapsResultList) {
            height += bitmap.getHeight();
        }
        if (height > LONG_BITMAP_HEIGHT_LIMIT) {
            Log.w(TAG, "Limit height reached.");
            return true;
        }
        return false;
    }

    private Bitmap captureScreenshotBitmap() {
        mDisplay.getRealMetrics(mDisplayMetrics);
        float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
        int rot = mDisplay.getRotation();

        Rect sourceCrop = new Rect(0, 0, (int) dims[0], (int) dims[1]);
        // Take the screenshot
        Bitmap bitmap = SurfaceControl.screenshot(sourceCrop, (int) dims[0], (int) dims[1], rot);
        Log.d(TAG, "capture screenshot bitmap");
        if (bitmap == null) {
            Log.d(TAG, "capture screenshot bitmap is null!");
        }
        return bitmap;
    }

    /**
     * @param context everything needs a context :(
     */
    @Inject
    public GlobalScreenshotMoreAction(
            Context context, @Main Resources resources, LayoutInflater layoutInflater,
            ScreenshotNotificationsController screenshotNotificationsController) {
        mContext = context;
        mNotificationsController = screenshotNotificationsController;

        // Inflate the screenshot layout
        mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot_more_action, null);
        mMoreActionLayout = layoutInflater.inflate(R.layout.global_screenshot_more_action_selector, null);
        mLongScreenshotTips = layoutInflater.inflate(R.layout.global_longscreenshot_tips, null);
        mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_background);
        mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot);
        mImageview = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_image);
        mScreenshotView.setClipToOutline(true);
        mScreenshotView.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
                        ROUNDED_CORNER_RADIUS * view.getWidth());
            }
        });

        mActionsContainer = mScreenshotLayout.findViewById(
                R.id.global_screenshot_actions_container);
        mActionsView = mScreenshotLayout.findViewById(R.id.global_screenshot_actions);
        mBackgroundProtection = mScreenshotLayout.findViewById(
                R.id.global_screenshot_actions_background);
        mDismissButton = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_button);
        mDismissButton.setOnClickListener(view -> {
            clearScreenshot("dismiss_button");
            enableAssistantIfNeeded(mContext);//unisoc: modify for bug1362660
            setRegionOrLongshotMode(mContext, 0);
            mOnCompleteRunnable.run();
        });

        mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
        mScreenshotMoreActionSelectorView = (ScreenshotMoreActionSelectorView) mMoreActionLayout
                .findViewById(R.id.screen_shot_select_view);
        mScreenshotLayout.setFocusable(true);
        mScreenshotMoreActionSelectorView.setFocusable(true);
        mScreenshotMoreActionSelectorView.setFocusableInTouchMode(true);
        mScreenshotView.setPivotX(0);
        mScreenshotView.setPivotY(0);
        mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // Intercept and ignore all touch events
                return true;
            }
        });
        mMoreActionLayout.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
            @Override
            public void onViewDetachedFromWindow(View v) {
            }

            @Override
            public void onViewAttachedToWindow(View v) {
            }
        });
        mPreviousBitmap = null;
        mCropedBitmapsResultList = new ArrayList<>();

        // Setup the window that we are going to use
        mWindowLayoutParams = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
                WindowManager.LayoutParams.TYPE_SCREENSHOT,
                WindowManager.LayoutParams.FLAG_FULLSCREEN
                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
                PixelFormat.TRANSLUCENT);
        mWindowLayoutParams.setTitle("ScreenshotAnimation");
        mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        mWindowLayoutParams.setFitInsetsTypes(0 /* types */);

        mMoreActionWindowLayoutParams = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
                WindowManager.LayoutParams.TYPE_SCREENSHOT,
                WindowManager.LayoutParams.FLAG_FULLSCREEN
                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                PixelFormat.TRANSLUCENT);
        mMoreActionWindowLayoutParams.setTitle("MoreActionLayoutWindow");
        mMoreActionWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        mMoreActionWindowLayoutParams.gravity = Gravity.TOP;

        mLongScreenshotTipLayoutParams = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0,
                WindowManager.LayoutParams.TYPE_SCREENSHOT,
                WindowManager.LayoutParams.FLAG_FULLSCREEN
                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                PixelFormat.TRANSLUCENT);
        mLongScreenshotTipLayoutParams.setTitle("LongScreenshotTipWindow");
        mLongScreenshotTipLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        mLongScreenshotTipLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        mLongScreenshotTipLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;

        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        mDisplay = mWindowManager.getDefaultDisplay();
        mDisplayMetrics = new DisplayMetrics();
        mDisplay.getRealMetrics(mDisplayMetrics);
        mDensity = mDisplayMetrics.density;
        mScreenshotOffsetXPx = resources.getDimensionPixelSize(R.dimen.screenshot_offset_x);
        mScreenshotOffsetYPx = resources.getDimensionPixelSize(R.dimen.long_screenshot_offset_y); // UNISOC: Modify for bug1411164
        mScreenshotHeightPx =
                resources.getDimensionPixelSize(R.dimen.screenshot_action_container_offset_y);
        mDismissButtonSize = resources.getDimensionPixelSize(
                R.dimen.screenshot_dismiss_button_tappable_size);
        mCornerSizeX = resources.getDimensionPixelSize(R.dimen.global_screenshot_x_scale);

        mFastOutSlowIn =
                AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_slow_in);

        // Setup the Camera shutter sound
        mCameraSound = new MediaActionSound();
        mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
        // UNISOC: Modify for bug1389430
        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(ACTION_SR_CHANGING),
                false, mScreenResolutionObserver);
    }

    @Override // ViewTreeObserver.OnComputeInternalInsetsListener
    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
        inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
        Region touchRegion = new Region();

        Rect screenshotRect = new Rect();
        mScreenshotView.getBoundsOnScreen(screenshotRect);
        touchRegion.op(screenshotRect, Region.Op.UNION);
        Rect actionsRect = new Rect();
        mActionsContainer.getBoundsOnScreen(actionsRect);
        touchRegion.op(actionsRect, Region.Op.UNION);
        Rect dismissRect = new Rect();
        mDismissButton.getBoundsOnScreen(dismissRect);
        touchRegion.op(dismissRect, Region.Op.UNION);

        inoutInfo.touchableRegion.set(touchRegion);
    }

    /**
     * Creates a new worker thread and saves the screenshot to the media store.
     */
    private void saveScreenshotInWorkerThread(@Nullable GlobalScreenshot.ActionsReadyListener actionsReadyListener) {
        GlobalScreenshot.SaveImageInBackgroundData data = new GlobalScreenshot.SaveImageInBackgroundData();
        data.image = mScreenBitmap;
        data.finisher = mFinisher;
        data.mActionsReadyListener = actionsReadyListener;
        if (mSaveInBgTask != null) {
            mSaveInBgTask.cancel(false);
        }

        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data).execute();
    }

    /**
     * Creates a new worker thread and saves the screenshot to the media store.
     */
    private void saveLongScreenshotInWorkerThread(@Nullable GlobalScreenshot.ActionsReadyListener actionsReadyListener) {
        GlobalScreenshot.SaveImageInBackgroundData data = new GlobalScreenshot.SaveImageInBackgroundData();
        data.image = getCapturedBitmap();
        data.finisher = mFinisher;
        data.mActionsReadyListener = actionsReadyListener;
        if (mSaveInBgTask != null) {
            mSaveInBgTask.cancel(false);
        }

        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data).execute();
    }

    /**
     * Takes a screenshot of the current display and shows an animation.
     */
    private void takeScreenshot(Rect crop) {
        clearScreenshot("new screenshot requested");
        onConfigChanged(mContext.getResources().getConfiguration());//Modify for bug 1363732
        int rot = mDisplay.getRotation();
        int width = crop.width();
        int height = crop.height();

        Rect screenRect = new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels);

        takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), screenRect);
    }
    /* UNISOC: Modify for bug 1363732 1360505{@ */
    private void onConfigChanged(Configuration newConfig) {
        boolean needsUpdate = false;
        if (mDisplayMetrics.density != mDensity) {
            mDensity = mDisplayMetrics.density;
            needsUpdate = true;
        }
        // dark mode
        if (newConfig.isNightModeActive()) {
            // Night mode is active, we're using dark theme
            if (!mInDarkMode) {
                mInDarkMode = true;
                mImageview.setImageResource(R.drawable.screenshot_cancel);
            }
        } else {
            // Night mode is not active, we're using the light theme
            if (mInDarkMode) {
                mInDarkMode = false;
                mImageview.setImageResource(R.drawable.screenshot_cancel);
            }
        }
        if (needsUpdate) {
            reloadAssets();
        }
    }
    /* @}  */
    /* UNISOC: Modify for bug 1360505{@ */
    private void reloadAssets() {
        mScreenshotLayout = LayoutInflater.from(mContext).inflate(R.layout.global_screenshot_more_action, null);
        mMoreActionLayout = LayoutInflater.from(mContext).inflate(R.layout.global_screenshot_more_action_selector, null);
        mLongScreenshotTips = LayoutInflater.from(mContext).inflate(R.layout.global_longscreenshot_tips, null);
        mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_background);
        mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot);
        mScreenshotView.setClipToOutline(true);
        mScreenshotView.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
                        ROUNDED_CORNER_RADIUS * view.getWidth());
            }
        });
        mBackgroundProtection = mScreenshotLayout.findViewById(
                R.id.global_screenshot_actions_background);
        mDismissButton = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_button);
            mDismissButton.setOnClickListener(view -> {
            clearScreenshot("dismiss_button");
            enableAssistantIfNeeded(mContext);//unisoc: modify for bug1362660
            setRegionOrLongshotMode(mContext, 0);
            mOnCompleteRunnable.run();
        });
        mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
        mScreenshotMoreActionSelectorView = (ScreenshotMoreActionSelectorView) mMoreActionLayout
                .findViewById(R.id.screen_shot_select_view);
        mScreenshotView.setPivotX(0);
        mScreenshotView.setPivotY(0);
        mScreenshotOffsetXPx =  mContext.getResources().getDimensionPixelSize(R.dimen.screenshot_offset_x);
        mScreenshotOffsetYPx =  mContext.getResources().getDimensionPixelSize(R.dimen.long_screenshot_offset_y); // UNISOC: Modify for bug1411164
        mScreenshotHeightPx =
                 mContext.getResources().getDimensionPixelSize(R.dimen.screenshot_action_container_offset_y);
        mDismissButtonSize =  mContext.getResources().getDimensionPixelSize(
                R.dimen.screenshot_dismiss_button_tappable_size);
        mCornerSizeX =  mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_x_scale);
    }
    /* @}  */
    private void initSelectorView() {
        mScreenshotMoreActionSelectorView.setCurrentForLongScreenShot(true);
        mScreenshotMoreActionSelectorView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (v instanceof ScreenshotMoreActionSelectorView) {
                    ScreenshotMoreActionSelectorView view = (ScreenshotMoreActionSelectorView) v;
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            view.updateCurrentSelectionCircle((int) event.getX(), (int) event.getY());
                            return true;
                        case MotionEvent.ACTION_MOVE:
                            view.updateRegionSelection((int) event.getX(), (int) event.getY());
                            return true;
                        case MotionEvent.ACTION_UP:
                            return true;
                    }
                }

                return false;
            }
        });
        mScreenshotLayout.post(new Runnable() {
            @Override
            public void run() {
                mScreenshotMoreActionSelectorView.setVisibility(View.VISIBLE);
                mScreenshotMoreActionSelectorView.requestFocus();
            }
        });
    }

    private void takeScreenshot(Bitmap screenshot, Rect screenRect) {
        mScreenBitmap = screenshot;
        if (mScreenBitmap == null) {
            mNotificationsController.notifyScreenshotError(
                    R.string.screenshot_failed_to_capture_text);
            mFinisher.accept(null);
            setRegionOrLongshotMode(mContext, 0);
            mOnCompleteRunnable.run();
            return;
        }

        initSelectorView();

        // Optimizations
        mScreenBitmap.setHasAlpha(false);
        mScreenBitmap.prepareToDraw();

        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
        mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);

        // Start the post-screenshot animation
        startAnimation(screenRect.width(), screenRect.height(), screenRect);
    }

    void takeScreenshot(Consumer<Uri> finisher, Runnable onComplete) {
        if (isInRegionOrLongshotMode(mContext)) {
            Log.d(TAG, "current aready in mode!");
            return;
        }
        setRegionOrLongshotMode(mContext, 1);
        mFinisher = finisher;
        mOnCompleteRunnable = onComplete;
        mDisplay.getRealMetrics(mDisplayMetrics);
        takeScreenshot(new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
    }

    /**
     * Cancels screenshot request
     */
    void stopScreenshot() {
        enableAssistantIfNeeded(mContext);//unisoc: modify for bug1353966
        // If the selector layer still presents on screen, we remove it and resets its state.
        if (mScreenshotMoreActionSelectorView.getSelectionRect() != null) {
            mWindowManager.removeView(mScreenshotLayout);
            mScreenshotMoreActionSelectorView.stopSelection();

            if (mMoreActionLayout.isAttachedToWindow()) {
                mWindowManager.removeView(mMoreActionLayout);
            }
        }
        if (mScreenshotHandler.hasMessages(MESSAGE_CORNER_TIMEOUT)) {
            clearScreenshot("stop screenshot");
            setRegionOrLongshotMode(mContext, 0);
            mOnCompleteRunnable.run();
        }
    }

    /**
     * Clears current screenshot
     */
    private void clearScreenshot(String reason) {
        Log.e(TAG, "clearing screenshot: " + reason);
        if (mScreenshotLayout.isAttachedToWindow()) {
            mWindowManager.removeView(mScreenshotLayout);
        }
        mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
        mScreenshotLayout.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);

        // Clear any references to the bitmap
        mScreenshotView.setImageBitmap(null);
        mActionsContainer.setVisibility(View.GONE);
        mBackgroundView.setVisibility(View.GONE);
        mBackgroundProtection.setAlpha(0f);
        mDismissButton.setVisibility(View.GONE);
        mScreenshotView.setVisibility(View.GONE);
        mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
        mPreviousBitmap = null;
        mIsLongscreenshotStarting = false;
        mCropedBitmapsResultList.clear();
    }

    protected Bitmap getCapturedBitmap() {
        if (mCropedBitmapsResultList == null || mPreviousBitmap == null
                || mCropedBitmapsResultList.size() <= 1) {
            Log.d(TAG, "use mScreenBitmap");
            return mScreenBitmap;
        }
        if (!mDuplicateNotFound) {
            Bitmap capturedBitmap = mPreviousBitmap;
            //UNISOC:Modify for bug 1361055
            Bitmap bottomBitmap = Bitmap.createBitmap(capturedBitmap, 0,
                    capturedBitmap.getHeight() - (int)(mScreenBitmap.getHeight() / 4 * getScale()),
                    capturedBitmap.getWidth(), (int)(mScreenBitmap.getHeight() / 4 * getScale()));
            mCropedBitmapsResultList.add(bottomBitmap);
            Log.d(TAG, "add bottom bitmap:" + bottomBitmap.getHeight());
        }
        return mergeBitmaps(mCropedBitmapsResultList);
    }

    private static Bitmap mergeBitmaps(List<Bitmap> bitmaps) {
        if (bitmaps.size() == 0) return null;
        if (bitmaps.size() == 1) return bitmaps.get(0);
        int height = 0;
        for (int i = 0; i < bitmaps.size(); i++) {
            Bitmap bitmap = bitmaps.get(i);
            height += bitmap.getHeight();
        }

        Bitmap result = Bitmap.createBitmap(bitmaps.get(0).getWidth(), height, Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(result);
        int currentHight = 0;
        for (int i = 0; i < bitmaps.size(); i++) {
            Bitmap bitmap = bitmaps.get(i);
            if (!canvas.isHardwareAccelerated()) {
                bitmap = bitmaps.get(i).copy(Bitmap.Config.ARGB_8888, true);
            }
            canvas.drawBitmap(bitmap, 0, currentHight, null);
            canvas.save(Canvas.ALL_SAVE_FLAG);
            canvas.restore();
            currentHight += bitmap.getHeight();
        }

        for (Bitmap b : bitmaps) {
            if (b != null) {
                b.recycle();
            }
        }
        bitmaps.clear();

        return result;
    }

    /**
     * Starts the animation after taking the screenshot
     */
    private void startAnimation(int w, int h, @Nullable Rect screenRect) {
        // If power save is on, show a toast so there is some visual indication that a screenshot
        // has been taken.
        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        if (powerManager.isPowerSaveMode()) {
            Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show();
        }

        // Add the view for the animation
        mScreenshotView.setImageBitmap(mScreenBitmap);

        mScreenshotAnimation = createScreenshotDropInAnimation(w, h, screenRect);

        mScreenshotHandler.post(() -> {
            // Dont play the shutter sound when we taken a longscreenshot
            //mCameraSound.play(MediaActionSound.SHUTTER_CLICK);

            mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
            mScreenshotView.buildLayer();
            mScreenshotAnimation.start();
        });
    }

    private AnimatorSet createScreenshotDropInAnimation(int width, int height, Rect bounds) {
        float cornerScale = mCornerSizeX / (float) width;

        AnimatorSet dropInAnimation = new AnimatorSet();
        ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1);
        flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS);
        flashInAnimator.setInterpolator(mFastOutSlowIn);
        flashInAnimator.addUpdateListener(animation ->
                mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));

        ValueAnimator flashOutAnimator = ValueAnimator.ofFloat(1, 0);
        flashOutAnimator.setDuration(SCREENSHOT_FLASH_OUT_DURATION_MS);
        flashOutAnimator.setInterpolator(mFastOutSlowIn);
        flashOutAnimator.addUpdateListener(animation ->
                mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));

        final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
        final PointF finalPos = new PointF(mScreenshotOffsetXPx + width * cornerScale / 2f,
                mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale / 2f);

        ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
        toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
        float xPositionPct =
                SCREENSHOT_TO_CORNER_X_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
        float scalePct =
                SCREENSHOT_TO_CORNER_SCALE_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
        toCorner.addUpdateListener(animation -> {
            float t = animation.getAnimatedFraction();
            if (t < scalePct) {
                float scale = MathUtils.lerp(
                        1, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct));
                mScreenshotView.setScaleX(scale);
                mScreenshotView.setScaleY(scale);
            } else {
                mScreenshotView.setScaleX(cornerScale);
                mScreenshotView.setScaleY(cornerScale);
            }

            if (t < xPositionPct) {
                float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
                        mFastOutSlowIn.getInterpolation(t / xPositionPct));
                mScreenshotView.setX(xCenter - width * mScreenshotView.getScaleX() / 2f);
            } else {
                mScreenshotView.setX(finalPos.x - width * mScreenshotView.getScaleX() / 2f);
            }
            float yCenter = MathUtils.lerp(startPos.y, finalPos.y,
                    mFastOutSlowIn.getInterpolation(t));
            mScreenshotView.setY(yCenter - height * mScreenshotView.getScaleY() / 2f);
        });

        toCorner.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                mScreenshotView.setVisibility(View.VISIBLE);
            }
        });

        mScreenshotFlash.setAlpha(0f);
        mScreenshotFlash.setVisibility(View.GONE);

        dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
        dropInAnimation.play(flashOutAnimator).with(toCorner);

        dropInAnimation.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mScreenshotView.setScaleX(cornerScale);
                mScreenshotView.setScaleY(cornerScale);
                mScreenshotView.setX(finalPos.x - width * cornerScale / 2f);
                mScreenshotView.setY(finalPos.y - height * cornerScale / 2f);
                Rect bounds = new Rect();
                mScreenshotView.getBoundsOnScreen(bounds);
                mScreenshotView.setEnabled(true);
                mDismissButton.setX(bounds.right - mDismissButtonSize / 2f);
                mDismissButton.setY(bounds.top - mDismissButtonSize / 2f);
                mDismissButton.setVisibility(View.VISIBLE);
                mScreenshotView.setOnClickListener(v -> {
                    mScreenshotView.setEnabled(false);
                    mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
                    mDismissButton.setVisibility(View.GONE);
                    AnimatorSet animatorSet = createScreenshotRegionDropInAnimation(width, height, bounds);
                    animatorSet.start();
                });
                mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
                mScreenshotHandler.sendMessageDelayed(
                        mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
                        SCREENSHOT_CORNER_TIMEOUT_MILLIS);
                registerStopLongScreenshotReceiver();
            }
        });

        return dropInAnimation;
    }

    private AnimatorSet createScreenshotRegionDropInAnimation(int width, int height, Rect bounds) {
        float cornerScale = mCornerSizeX / (float) width;

        AnimatorSet dropInAnimation = new AnimatorSet();
        ValueAnimator flashInAnimator = ValueAnimator.ofFloat(1, 0);
        flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS);
        flashInAnimator.setInterpolator(mFastOutSlowIn);
        flashInAnimator.addUpdateListener(animation ->
                mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));

        ValueAnimator flashOutAnimator = ValueAnimator.ofFloat(0, 1);
        flashOutAnimator.setDuration(SCREENSHOT_FLASH_OUT_DURATION_MS);
        flashOutAnimator.setInterpolator(mFastOutSlowIn);
        flashOutAnimator.addUpdateListener(animation ->
                mScreenshotFlash.setAlpha((float) animation.getAnimatedValue()));

        final PointF startPos = new PointF(mScreenshotOffsetXPx + width * cornerScale / 2f,
                mDisplayMetrics.heightPixels - mScreenshotOffsetYPx - height * cornerScale / 2f);
        final PointF finalPos = new PointF(width * (1 - SCREENSHOT_MORE_ACTION_DROP_IN_SCALE) / 2,
                height * (1 - SCREENSHOT_MORE_ACTION_DROP_IN_SCALE) / SCREENSHOT_TOP_MAGIN_SPLIT_HEIGHT_COUNT);

        ValueAnimator toCenter = ValueAnimator.ofFloat(1, 0);
        toCenter.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
        float xPositionPct =
                SCREENSHOT_TO_CORNER_X_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
        toCenter.addUpdateListener(animation -> {
            float t = animation.getAnimatedFraction();
            float targetScale = t * SCREENSHOT_MORE_ACTION_DROP_IN_SCALE * (mDisplayMetrics.scaledDensity - 1);

            if (targetScale > cornerScale && targetScale < SCREENSHOT_MORE_ACTION_DROP_IN_SCALE) {
                mScreenshotView.setScaleX(targetScale);
                mScreenshotView.setScaleY(targetScale);
            }

            if (t < xPositionPct) {
                float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
                        mFastOutSlowIn.getInterpolation(t / xPositionPct));
                mScreenshotView.setX(xCenter);
            } else {
                mScreenshotView.setX(finalPos.x);
            }
            float yCenter = MathUtils.lerp(startPos.y, finalPos.y,
                    mFastOutSlowIn.getInterpolation(t));
            mScreenshotView.setY(yCenter);
            mBackgroundView.setAlpha(t);
        });

        toCenter.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                mScreenshotView.setVisibility(View.VISIBLE);

                mBackgroundView.setAlpha(0f);
                mBackgroundView.setVisibility(View.VISIBLE);
                sendLongscreenshotBroadcast();
            }
        });

        dropInAnimation.play(flashInAnimator).with(toCenter);

        dropInAnimation.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mScreenshotView.setScaleX(SCREENSHOT_MORE_ACTION_DROP_IN_SCALE);
                mScreenshotView.setScaleY(SCREENSHOT_MORE_ACTION_DROP_IN_SCALE);
                mScreenshotView.setX(finalPos.x);
                mScreenshotView.setY(finalPos.y);

                if (mMoreActionLayout.isAttachedToWindow()) {
                    mWindowManager.removeView(mMoreActionLayout);
                }
                mWindowManager.addView(mMoreActionLayout, mMoreActionWindowLayoutParams);
                int[] location = new int[2];
                float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
                mScreenshotView.getLocationOnScreen(location);
                mScreenshotMoreActionSelectorView.startRegionSelection((int) dims[0], (int) dims[1], location);

                initButtonActions();
            }
        });

        return dropInAnimation;
    }

    private void initButtonActions() {
        View btnCancel = (View) mMoreActionLayout.findViewById(R.id.btn_cancel);
        View btnShare = (View) mMoreActionLayout.findViewById(R.id.btn_share);
        View btnSave = (View) mMoreActionLayout.findViewById(R.id.btn_save);
        View btnScrollMode = (View) mMoreActionLayout.findViewById(R.id.btn_scroll_mode);

        // set textview size for constant
        float pixelSize = mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_more_action_text_size);
        float spSize = px2sp(mContext, pixelSize);
        ((TextView) btnScrollMode.findViewById(R.id.btn_scroll_tv)).setTextSize(spSize);
        ((TextView) btnCancel.findViewById(R.id.btn_cancel_tv)).setTextSize(spSize);
        ((TextView) btnShare.findViewById(R.id.btn_share_tv)).setTextSize(spSize);
        ((TextView) btnSave.findViewById(R.id.btn_save_tv)).setTextSize(spSize);
        float tipSize = mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_tips_size);
        float tipSpSize = px2sp(mContext, tipSize);
        setLongScreenshotTipsSize(tipSpSize);

        ((ImageView) btnScrollMode.findViewById(R.id.btn_scroll_icon)).setImageResource(R.drawable.screenshot_more_action);
        ((ImageView) btnCancel.findViewById(R.id.btn_cancel_icon)).setImageResource(com.android.internal.R.drawable.ic_menu_revert);
        ((ImageView) btnShare.findViewById(R.id.btn_share_icon)).setImageResource(com.android.internal.R.drawable.ic_menu_share);
        ((ImageView) btnSave.findViewById(R.id.btn_save_icon)).setImageResource(com.android.internal.R.drawable.ic_menu_save);

        int imgPixelSize = (int) mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_more_action_icon_size);
        ((ImageView) btnScrollMode.findViewById(R.id.btn_scroll_icon)).getLayoutParams().height = imgPixelSize;
        ((ImageView) btnScrollMode.findViewById(R.id.btn_scroll_icon)).getLayoutParams().width = imgPixelSize;
        ((ImageView) btnCancel.findViewById(R.id.btn_cancel_icon)).getLayoutParams().height = imgPixelSize;
        ((ImageView) btnCancel.findViewById(R.id.btn_cancel_icon)).getLayoutParams().width = imgPixelSize;
        ((ImageView) btnShare.findViewById(R.id.btn_share_icon)).getLayoutParams().height = imgPixelSize;
        ((ImageView) btnShare.findViewById(R.id.btn_share_icon)).getLayoutParams().width = imgPixelSize;
        ((ImageView) btnSave.findViewById(R.id.btn_save_icon)).getLayoutParams().height = imgPixelSize;
        ((ImageView) btnSave.findViewById(R.id.btn_save_icon)).getLayoutParams().width = imgPixelSize;

        ((TextView) btnCancel.findViewById(R.id.btn_cancel_tv)).setText(mContext.getString(com.android.internal.R.string.cancel));
        ((TextView) btnSave.findViewById(R.id.btn_save_tv)).setText(mContext.getString(R.string.save));
        ((TextView) btnShare.findViewById(R.id.btn_share_tv)).setText(mContext.getString(com.android.internal.R.string.share));
        setScrollViewText(mContext.getString(R.string.long_screen_shot));

        KeyguardManager keyguardManager =
                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
        if (keyguardManager.isKeyguardLocked()) {
            btnShare.setVisibility(View.GONE);
            btnScrollMode.setVisibility(View.INVISIBLE);
        } else {
            btnShare.setVisibility(View.VISIBLE);
            btnScrollMode.setVisibility(View.VISIBLE);
        }
        mMoreActionLayout.findViewById(R.id.more_action_layout).setVisibility(View.VISIBLE);
        btnCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mMoreActionLayout.findViewById(R.id.more_action_layout).setVisibility(View.INVISIBLE);
                stopScreenshot();
                setRegionOrLongshotMode(mContext, 0);
                mOnCompleteRunnable.run();
            }
        });
        btnShare.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mMoreActionLayout.findViewById(R.id.more_action_layout).setVisibility(View.INVISIBLE);
                shareScreenshot();
            }
        });
        btnSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mMoreActionLayout.findViewById(R.id.more_action_layout).setVisibility(View.INVISIBLE);
                //editScreenshot();
                saveScreenshot();
            }
        });
        btnScrollMode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mMoreActionLayout.findViewById(R.id.more_action_layout).setVisibility(View.INVISIBLE);
                if (mIsMultiWindowMode) {
                    stopScreenshot();
                    Toast.makeText(mContext, R.string.tip_not_support_in_split_screen, Toast.LENGTH_SHORT).show();
                    return;
                }

                if (!mIsLongscreenshotStarting) {
                    mScreenshotMoreActionSelectorView.setVisibility(View.GONE);
                    mIsCancelLongScreenshot = false;
                    mDuplicateNotFound = false;
                    mCompleteLongScreenshot = false;

                    stopScreenshot();
                    startLongscreenshot();
                }
            }
        });
    }

    public void setScreenshotService(TakeScreenshotService service) {
        mTakeScreenshotService = service;
    }

    private void registerStopLongScreenshotReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(LongScreenshotUtil.ACTION_STOP_LONGSCREENSHOT);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        filter.addAction(ACTION_PHONE_STATE_CHANGED);
        /*Unisoc:Fix for bug 1428157 @{ */
        if (UnisocPowerManagerUtil.SUPPORT_SUPER_POWER_SAVE) {
            filter.addAction(UnisocPowerManagerUtil.ACTION_POWEREX_SAVE_MODE_CHANGED);
        }
        /* @} */
        mContext.registerReceiver(mStopLongScreenshotReceiver, filter);
    }

    private void sendLongscreenshotBroadcast() {
        ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
        ComponentName cmp  = tasks.get(0).topActivity;

        String packageName = cmp.getPackageName();
        String activityName = cmp.getClassName();
        Intent intent = new Intent(LongScreenshotUtil.ACTION_LONGSCREENSHOT);
        intent.putExtra("package", packageName);
        intent.putExtra("activity", activityName);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
        Log.d(TAG, "sendLongscreenshotBroadcast: packageName=" + packageName + " activityName=" + activityName);
    }

    public void setMultiWindowMode(boolean mode) {
        mIsMultiWindowMode = mode;
    }

    protected void startLongscreenshot() {
        Log.d(TAG, "startLongscreenshot");
        disableAssistantIfNeeded(mContext);
        mIsLongscreenshotStarting = true;
        if (mLongScreenshotTips != null && mLongScreenshotTips.isAttachedToWindow()) {
            mWindowManager.removeView(mLongScreenshotTips);
        }
        mWindowManager.addView(mLongScreenshotTips, mLongScreenshotTipLayoutParams);
        setLongScreenshotTipsText(R.string.long_screenshot_tips);
        mTakeScreenshotService.sendLongscreenshotMessage(LongScreenshotUtil.MSG_START_LONG_SCREENSHOT);
        mScreenshotHandler.sendEmptyMessageDelayed(MSG_START_SWIPE, 500);
        prepareFirstBitmap();
    }

    public void cancelLongscreenshot() {
        Log.d(TAG, "cancelLongscreenshot");
        enableAssistantIfNeeded(mContext);
        if (mLongScreenshotTips != null && mLongScreenshotTips.isAttachedToWindow()) {
            mWindowManager.removeView(mLongScreenshotTips);
        }
        mTakeScreenshotService.sendLongscreenshotMessage(LongScreenshotUtil.MSG_STOP_LONG_SCREENSHOT);
        try {
            mContext.unregisterReceiver(mStopLongScreenshotReceiver);
        } catch (Exception ignore) {}
    }

    public void stopLongscreenshot() {
        Log.d(TAG, "stopLongscreenshot");
        setRegionOrLongshotMode(mContext, 0);
        enableAssistantIfNeeded(mContext);
        if (!mIsLongscreenshotStarting) return;//unisoc: modify for bug1330289
        cancelLongscreenshot();
        mOnCompleteRunnable.run();
    }

    public void stopLongscreenshotByUser() {
        Log.d(TAG, "stopLongscreenshotByUser");
        mCompleteLongScreenshot = true;
        setLongScreenshotTipsText(R.string.tip_merging);
    }

    private void shareScreenshot() {
        Log.d(TAG, "shareScreenshot");
        try {
            if (DEBUG_REGION) {
                mScreenshotMoreActionSelectorView.printLogs();
            }
            mScreenBitmap = getRealBitmapRegion();
        } catch (IllegalArgumentException e) {
            Log.d(TAG, "shareScreenshot error", e);
            mScreenBitmap.recycle();
            mScreenBitmap = null;
            return;
        }
        saveScreenshotInWorkerThread(new GlobalScreenshot.ActionsReadyListener() {
            @Override
            void onActionsReady(GlobalScreenshot.SavedImageData imageData) {
                /* UNISOC: Modify for bug 1417116 @{ */
                if (null == imageData.uri) {
                    mNotificationsController.notifyScreenshotError(
                            R.string.screenshot_failed_to_save_text);
                } else {
                    try {
                        imageData.shareAction.actionIntent.send();
                    } catch (PendingIntent.CanceledException e) {
                        Log.e(TAG, "Intent cancelled", e);
                    }
                    setRegionOrLongshotMode(mContext, 0);
                    mOnCompleteRunnable.run();
                }
                /* @} */
            }
        });
        stopScreenshot();
    }

    /* UNISOC: modify for Bug1330796 @{ */
    private void saveScreenshot() {
        Log.d(TAG, "saveScreenShot...");
        try {
            if (DEBUG_REGION) {
                mScreenshotMoreActionSelectorView.printLogs();
            }
            mScreenBitmap = getRealBitmapRegion();
            if (DEBUG_REGION) {
                Log.d(TAG, "saveScreenshot after mScreenBitmap.getWidth:" + mScreenBitmap.getWidth()
                        + " mScreenBitmap.getHeight:" + mScreenBitmap.getHeight());
            }
        } catch (IllegalArgumentException e) {
            Log.d(TAG, "saveScreenShot error", e);
            // TODO: handle exception
            e.printStackTrace();
            clearScreenshot("save_error");//unisoc:modify for bug1360387
            mNotificationsController.notifyScreenshotError(
                    R.string.screenshot_failed_to_save_unknown_text);
            mScreenBitmap.recycle();
            mScreenBitmap = null;
            return;
        }
        saveScreenshotInWorkerThread(new GlobalScreenshot.ActionsReadyListener() {
            @Override
            void onActionsReady(GlobalScreenshot.SavedImageData imageData) {
                setRegionOrLongshotMode(mContext, 0);
                mOnCompleteRunnable.run();
                /* UNISOC: Modify for bug 1417116 @{ */
                if (null == imageData.uri) {
                    mNotificationsController.notifyScreenshotError(
                            R.string.screenshot_failed_to_save_text);
                } else {
                    /* UNISOC: Modify for bug1362580 @{ */
                    mScreenshotHandler.post(() -> {
                        Toast.makeText(mContext, R.string.screenshot_saved_title,
                                Toast.LENGTH_SHORT).show();
                    });
                    /* @} */
                }
                /* @} */
            }
        });
        stopScreenshot();
    }
    /* @} */

    private void editScreenshot() {
        Log.d(TAG, "editScreenshot");
        try {
            if (DEBUG_REGION) {
                mScreenshotMoreActionSelectorView.printLogs();
            }
            mScreenBitmap = getRealBitmapRegion();
            if (DEBUG_REGION) {
                Log.d(TAG, "editScreenshot after mScreenBitmap.getWidth:" + mScreenBitmap.getWidth()
                        + " mScreenBitmap.getHeight:" + mScreenBitmap.getHeight());
            }
        } catch (IllegalArgumentException e) {
            Log.d(TAG, "editScreenshot error", e);
            mScreenBitmap.recycle();
            mScreenBitmap = null;
            return;
        }
        saveScreenshotInWorkerThread(new GlobalScreenshot.ActionsReadyListener() {
            @Override
            void onActionsReady(GlobalScreenshot.SavedImageData imageData) {
                try {
                    imageData.editAction.actionIntent.send();
                } catch (PendingIntent.CanceledException e) {
                    Log.e(TAG, "Intent cancelled", e);
                }
                setRegionOrLongshotMode(mContext, 0);
                mOnCompleteRunnable.run();
            }
        });
        stopScreenshot();
    }

    private Bitmap getRealBitmapRegion() {
        if (DEBUG_REGION) {
            Log.d(TAG, "getRealBitmapRegion begin"
                    + "\nx:" + mScreenshotMoreActionSelectorView.getRealSelectionLocationX()
                    + "\nw:" + mScreenshotMoreActionSelectorView.getRealSelectionRegionWidth()
                    + "\ny:" + mScreenshotMoreActionSelectorView.getRealSelectionLocationY()
                    + "\nh:" + mScreenshotMoreActionSelectorView.getRealSelectionRegionHeight()
                    + "\nmScreenBitmap.getWidth():" + mScreenBitmap.getWidth()
                    + "\nmScreenBitmap.getHeight():" + mScreenBitmap.getHeight());
        }
        // Crop the screenshot to selected region
        Bitmap cropped = Bitmap.createBitmap(mScreenBitmap,
                mScreenshotMoreActionSelectorView.getRealSelectionLocationX(),
                mScreenshotMoreActionSelectorView.getRealSelectionLocationY(),
                mScreenshotMoreActionSelectorView.getRealSelectionRegionWidth(),
                mScreenshotMoreActionSelectorView.getRealSelectionRegionHeight());
        if (cropped.getWidth() != mScreenBitmap.getWidth()
                || cropped.getHeight() != mScreenBitmap.getHeight()) {
            mScreenBitmap.recycle();
        }
        if (DEBUG_REGION) {
            Log.d(TAG, "getRealBitmapRegion end");
        }
        return cropped;
    }

    private static int px2sp(Context context, float pxValue) {
        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }

    private void setLongScreenshotTipsSize(float size) {
        TextView tipsView = (TextView) mLongScreenshotTips.findViewById(R.id.tv_tips);
        if (tipsView != null) {
            tipsView.setTextSize(size);
        }
    }

    private void setLongScreenshotTipsText(int res) {
        TextView tipsView = (TextView) mLongScreenshotTips.findViewById(R.id.tv_tips);
        if (tipsView != null) {
            tipsView.setText(res);
        }
    }

    private void setScrollViewText(String text) {
        if (mMoreActionLayout != null) {
            ((TextView) mMoreActionLayout.findViewById(R.id.btn_scroll_tv)).setText(text);
        }
    }

    /* UNISOC: Modify for bug1404134 @{ */
    public void cancelAll() {
        mIsCancelLongScreenshot = true;
        try {
            mMoreActionLayout.findViewById(R.id.more_action_layout).setVisibility(View.INVISIBLE);
            stopScreenshot();
            stopLongscreenshot();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /* @} */
}
